home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-05-21 | 5.5 KB | 232 lines | [TEXT/ttxt] |
- --<<
-
- in module InternetFish
-
- -- Connection Manager:
- -- It is responsible for managing connections with other instances of itself
- -- running on different machines. ConnectionManagers exchange [host,port]
- -- information so each CM can be connected to all other CMs
-
- class ConnectionManager ()
- instance variables
- -- array of connections
- connections : (new array)
- client
- tcpListen
- myPort
- end
-
- method init self {object connectionManager} #key port: port client: client -> (
- self.client := client
- self.myPort := port
- addconnection self (new connection host: (getIPAddress tcpstream) port: port client: self)
- self.tcplisten := new tcpstream port: port listen: true
- startListening self &
- )
-
- method findConnection self {object ConnectionManager} stream -> (
- for c in self.connections do
- if c.tcpStream = stream do
- return c
- undefined
- )
-
- method findConnectionForHostPort self {object ConnectionManager} host port -> (
- for c in self.connections do
- if c.host = host and c.port = port do
- return c
- undefined
- )
-
- method removeConnection self {object ConnectionManager} c ->
- deleteOne self.connections c
-
- method addConnection self {object ConnectionManager} c -> (
- append self.connections c
- noteNewConnection self.client c (size self.connections = 2)
- )
-
- global rnd := new randomState
-
- method chooseConnection self {class ConnectionManager} -> (
- local n := (size self.connections)
- local i := random rnd (n - 1)
- i := i + 2
- for j in 2 to n do (
- if i > n do i := 2
- local c := self.connections[i]
- if c.tcpstream != undefined do (
- return c
- )
-
- i := i + 1
- )
- -- Are there any connections we can open?
- -- If not we have no one to talk to!
- return undefined
- )
-
-
-
- method isKnownAbout self {class ConnectionManager} addr port -> (
- for i in self.connections do
- if i.host = addr and i.port = port do return true
- return false
- )
-
- function readPort s -> (
- local a := read s
- local b := read s
- a * 256 + b
- )
-
- function writePort s p -> (
- local a := (p/256) as integer
- local b := mod p 256
- write s a
- write s b
- )
-
- function writeIPAddress s addr -> (
- for i in addr do write s i
- )
-
- function readIPAddress s -> (
- local addr := new quad
- for i in 1 to 4 do addr[i] := read s
- addr
- )
-
- method connectTo self {class ConnectionManager} host port -> (
- connectToServer self host port
- )
-
- method connectToSomeMore self {object ConnectionManager} -> (
- local i := 2
- repeat while i <= (size self.connections) do (
- local c := self.connections[i]
- if c.tcpstream = undefined then (
- guard (
- connectConnectionToServer self c
- i := i + 1
- )
- catching
- TCPException: (caught (removeConnection self c))
- --? Perhaps we get a cantread/write error also?
- end
- ) else
- i := i + 1
- )
- )
-
- method talkToServer self {object ConnectionManager} s -> (
- writePort s self.myPort
- writeKnownAbout self s
- readKnownAbout self s
- )
-
- method connectToServer self {object ConnectionManager} server port -> (
- -- Create a connection and open it
- -- This is contorted because we don't have a way of getting the ipaddress
- local s := new tcpstream host: server port: port
- local con := new connection client: self host: s.ipAddress port: port
- -- Assumes that we don't have a connection already
- addconnection self con
- completeConnection self con s
- )
-
- method connectConnectionToServer self {object ConnectionManager} con -> (
- --- Open an existing connection
- local s := new tcpstream host: con.host port: con.port
- completeConnection self con s
- )
-
- method completeConnection self {object ConnectionManager} con s -> (
- talkToServer self s
- openConnection con s
- con
- )
-
- method writeKnownAbout self {object ConnectionManager} s -> (
- -- This could change
- write s (size self.connections)
- for i in self.connections do (
- writeIPAddress s i.host
- writePort s i.port
- )
- flush s
- )
-
- method readKnownAbout self {object ConnectionManager} s -> (
- local n := read s
- for i in 1 to n do (
- local addr := readIPAddress s
- local port := readPort s
- if not (isKnownAbout self addr port) do
- addconnection self (new connection host: addr port: port client: self)
- )
- )
-
- method establishConnection self {object ConnectionManager} s -> (
- local port := readport s
- local host := s.ipaddress
- local c := findConnectionForHostPort self host port
- if c = undefined do (
- c := (new connection client: self host: host port: port)
- addconnection self c
- )
- -- This assumes that we don't already have a connection
- readKnownAbout self s
- writeKnownAbout self s
- openConnection c s
- )
-
- method startListening self {object ConnectionManager} -> (
- repeat while true do (
- local s := accept self.tcplisten
- establishConnection self s &
- )
- )
-
- method handleMessage self {object ConnectionManager} obj -> (
- if isakindof obj array do (
- if obj[1] = @readFailed then (
- handleReadError self obj[2]
- )
- else if obj[1] = @writeFailed then (
- handleWriteError self obj[2]
- )
- else
- handleNormalMessage self.client obj
- )
- )
-
- method handleWriteError self {object ConnectionManager} stream -> (
- handleDisconnect self stream
- )
-
- method handleReadError self {object ConnectionManager} stream -> (
- handleDisconnect self stream
- )
-
- method handleDisconnect self {object ConnectionManager} stream -> (
- local c := findConnection self stream
- removeConnection self c
- noteLostConnection self.client c
- )
-
- method disconnect self {object ConnectionManager} -> (
- local x := new array
- addmany x self.connections
- for c in x do
- if c.tcpstream != undefined do (
- -- This will cause errors which will cause the right thing to happen
- plug c.tcpstream
- c.tcpstream := undefined
- )
- )
-
- method stopListening self {object ConnectionManager} ->
- plug self.tcplisten
-
-